package com.jtpay.payresulthelper.http;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.jtpay.payresulthelper.BuildConfig;
import com.jtpay.payresulthelper.R;
import com.jtpay.payresulthelper.http.dataStructure.BasicResponse;
import com.jtpay.payresulthelper.http.dataStructure.JsonParams;
import com.jtpay.payresulthelper.http.listener.TransApiResultListener;
import com.jtpay.payresulthelper.http.loader.ApiLoader;
import com.jtpay.payresulthelper.http.retrofit.RetrofitBasicResponseObserver;
import com.jtpay.payresulthelper.http.retrofit.RetrofitObjectObserver;
import com.jtpay.payresulthelper.model.AliDbModel;
import com.jtpay.payresulthelper.provider.AliDbDataProvider;
import com.jtpay.payresulthelper.util.*;
import com.jtpay.payresulthelper.util.netWorkUtil.NetworkUtil;
import org.json.JSONException;
import org.json.JSONObject;

import static android.content.Context.TELEPHONY_SERVICE;
import static com.jtpay.payresulthelper.constant.HooKConstant.ACTION_QUERY_ORDER;
import static com.jtpay.payresulthelper.provider.AliDbDataProvider.*;
import static com.jtpay.payresulthelper.util.ApiConstant.*;
import static com.jtpay.payresulthelper.util.PayContext.*;


public class ApiHelper {
    private enum ApiEnum {
        //        ORI_API_NAME(""),
        REGISTER_API_NAME("注册"),
        NOTICES_API_NAME("支付通知"),
        PULSE_SPEED_API_NAME("打点"),
        AUTHORIZE_API_NAME("打点授权"),
        ACCOUNT_CHECK_API_NAME("账号验证"),
        TASK_API_NAME("获取任务");
        private final String message;

        ApiEnum(String message) {
            this.message = message;
        }

        public String getMessage() {
            return message;
        }
    }

    private Context mContext;
    private ApiLoader mApiLoader;
    private ApiLoader mLongTaskApiLoader;
    private JsonParams params;
    private String deviceId;
    private BasicResponse mBasicResponse;
    private SharedPreferenceUtil sharedPreferenceUtil = new SharedPreferenceUtil();
    private Handler handler = new Handler();
    private int longConnectStatus;//0 def (or new)  1 in do   2 end
    private boolean authorize;//
    private RetrofitBasicResponseObserver<BasicResponse<JsonObject>> pulseSpeedResponseObserver;
    private RetrofitBasicResponseObserver<BasicResponse<JsonObject>> taskApiServer;

    private static class Holder {
        @SuppressLint("StaticFieldLeak")
        private static final ApiHelper mHelper = new ApiHelper();
    }

    public Context getContext() {
        return mContext;
    }

    public boolean getAuthorize() {
        return authorize;
    }

    private void setContext(Context context) {
        if (context != null) {
            mContext = context;
        }
        mApiLoader = new ApiLoader();
    }

    /**
     * @return DeviceId
     */
    private String getDeviceId() {
        if (TextUtils.isEmpty(deviceId)) {
            TelephonyManager TelephonyMgr = (TelephonyManager) mContext.getSystemService(TELEPHONY_SERVICE);
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                sendMsg("getDeviceId", mContext.getString(R.string.no_read_phone_status_tips));
                return null;
            }
            deviceId = TelephonyMgr.getDeviceId();
        }
        return deviceId;
    }

    /**
     * @return sharedPreference store BasicResponse
     */
    private BasicResponse getBasicResponse() {
        if (mBasicResponse == null) {
            mBasicResponse = new Gson().fromJson(
                    sharedPreferenceUtil.SP_READ(mContext, SP_KEY_ALI_REGISTER_INFO)
                    , BasicResponse.class);
        }
        if (mBasicResponse == null) {
            mBasicResponse = new BasicResponse();
        }
        return mBasicResponse;
    }

    /**
     * @param response   BasicResponse
     * @param statusEnum ApiStatusEnum
     */
    private void updateBasicResponse(BasicResponse response, ApiEnum statusEnum) {
        BasicResponse basicResponse = getBasicResponse();
        switch (statusEnum) {
            case AUTHORIZE_API_NAME:
                basicResponse.setLongConnectionUrl(response.getLongConnectionUrl());
                break;
            case TASK_API_NAME:
                switch (response.getTaskType()) {
                    case 3:
                        basicResponse.setBeginTime(response.getBeginTime());
                        basicResponse.setEndTime(response.getEndTime());
                        basicResponse.setReason(response.getReason());
                        break;
                    case 4:
                        basicResponse.setBeginTime(response.getBeginTime());
                        basicResponse.setEndTime(response.getEndTime());
                        basicResponse.setSupplierOrderId(response.getSupplierOrderId());
                        break;
                    case 5:
                        basicResponse.setBeginTime(response.getBeginTime());
                        basicResponse.setEndTime(response.getEndTime());
                        break;
                    case 50:
                        basicResponse.setGrabOrderMode(response.getGrabOrderMode());
                        break;
                    case 80:
                        DEFAULT_TIMEOUT = response.getInterval();
                        sharedPreferenceUtil.SP_SAVE_INTEGER(mContext, SP_KEY_PULSE_SPEED, response.getInterval());
                        mApiLoader = null;
                        mLongTaskApiLoader = null;
                        break;
                }
                break;
        }
        sharedPreferenceUtil.SP_SAVE(mContext, SP_KEY_ALI_REGISTER_INFO, basicResponse.toString());
        mBasicResponse = null;
    }

    private ApiLoader getApiLoader() {
        if (mApiLoader == null) {
            mApiLoader = new ApiLoader(ApiConstant.getUrl(), DEFAULT_TIMEOUT);
        }
        return mApiLoader;
    }

    private ApiLoader getLongTaskApiLoader() {
        String longConnectUrl = getBasicResponse().getLongConnectionUrl();
        LogUtil.log("getLongTaskApiLoader longConnectUrl : " + longConnectUrl);
        if (mLongTaskApiLoader == null) {
            if (TextUtils.isEmpty(longConnectUrl) || !longConnectUrl.endsWith("/")) {
                sendMsg(ApiEnum.TASK_API_NAME.message, mContext.getString(R.string.long_connect_url_error));
                return null;
            }
            mLongTaskApiLoader = new ApiLoader(longConnectUrl, DEFAULT_LONG_CONNECT_TIMEOUT);
        }
        return mLongTaskApiLoader;
    }

    public static ApiHelper getInstance(Context context) {
        Holder.mHelper.setContext(context);
        return Holder.mHelper;
    }

    private JsonParams getNewParams() {
        if (params == null) {
            params = new JsonParams();
            return params;
        }
        params.clear();
        return params;
    }

    /**
     * pay result notice
     *
     * @param listener TransApiResultListener
     */
    public void noticeAPI(final int index, final AliDbModel model, final TransApiResultListener<String> listener) {
        params = getNewParams();
        params.put("systemcode", getBasicResponse().getSystemCode());
        params.put("handlerid", getBasicResponse().getHandlerId());
        params.put("money", model.getFormatMoney());
        params.put("reason", model.get_remark());
        params.put("payment", PAYMENT);
        params.put("time", model.get_time_stamp());
        params.put("remark", model.get_order_number());
        params.put("sign", getPaySign(model));
//        params.put("ver", "0.2");
        getApiLoader().postStrObserveRequestBody(ApiConstant.NOTICES_API, params)
                .subscribe(new RetrofitObjectObserver<String>(mContext) {
                    @Override
                    public void onSuccess(String response) {
                        super.onSuccess(response);
//                        LogUtil.log("getRegisterAPI : " + response.toString());
                        listener.trans(response);
                    }

                    @Override
                    public void onFail(String response) {
                        super.onFail(response);
                        listener.trans(response);
                        sendMsg(ApiEnum.NOTICES_API_NAME.message, response);
                        AliDbDataProvider.update(model.get_id(), "3", mContext);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        listener.trans(e.toString());
                        sendMsg(ApiEnum.NOTICES_API_NAME.message, e.toString());
                        noticeAgainDelay(index, model, listener);
                    }
                });
    }

    /**
     * noticeAgainDelay
     *
     * @param index    int
     * @param model    AliDbModel
     * @param listener TransApiResultListener<String>
     */
    private void noticeAgainDelay(int index, final AliDbModel model, final TransApiResultListener<String> listener) {
        index++;
        if (index > API_NOTICE_ERROR_COUNT_DEF) {
            sendMsg(ApiEnum.NOTICES_API_NAME.message, mContext.getString(R.string.api_error_time_limited));
            AliDbDataProvider.update(model.get_id(), "4", mContext);
            return;
        }
        sendMsg(ApiEnum.NOTICES_API_NAME.message, mContext.getString(R.string.notice_error_wait_for_next));
        final int finalIndex = index;
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                noticeAPI(finalIndex, model, listener);
            }
        }, index * DEFAULT_TIMEOUT * 1000L);
    }

    private String getPaySign(AliDbModel model) {
        String content = model.get_remark()
                + model.get_order_number()
                + model.getFormatMoney()
                + getBasicResponse().getSystemCode()
                + model.get_time_stamp()
                + PAYMENT
//                + getBasicResponse().getHandlerId()
                + PAY_RESULT_NOTICE_KEY;
        return PayMD5Util.getMD5(content);
    }

    /**
     * register api
     *
     * @param listener TransApiResultListener
     */
    public void getRegisterAPI(final String account, final TransApiResultListener<BasicResponse<JsonObject>> listener) {
        params = getNewParams();
        final String ip = NetworkUtil.getIPAddress();
        final String CpuId = getDeviceId();
        if (TextUtils.isEmpty(CpuId)) {
            sendMsg(ApiEnum.REGISTER_API_NAME.message, mContext.getString(R.string.device_info_error));
            return;
        }
        params.put("MechantAccount", account);
        params.put("CpuId", CpuId);
        params.put("IP", ip);
        params.put("PayType", PAYMENT);
        params.put("Version", BuildConfig.VERSION_NAME);
        getApiLoader().postJsonObserveJsonParam(ApiConstant.REGISTER_API, params)
                .subscribe(new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<JsonObject> response) {
                        super.onSuccess(response);
//                        LogUtil.log("getRegisterAPI : " + response.toString());
                        sharedPreferenceUtil.SP_SAVE(mContext, SP_KEY_ALI_REGISTER_INFO, response.toString());
                        sharedPreferenceUtil.SP_SAVE(mContext, SP_KEY_ALI_ACCOUNT_NAME, account);
                        ALI_ACCOUNT = account;
                        sharedPreferenceUtil.SP_SAVE(mContext, SP_KEY_DEVICE_IP, ip);
                        response.setMsg(HTTP_SUCCESS);
                        listener.trans(response);
                    }

                    @Override
                    public void onFail(BasicResponse<JsonObject> response) {
                        super.onFail(response);
                        listener.trans(response);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        BasicResponse<JsonObject> response = new BasicResponse<>();
                        response.setMsg(e.toString());
                        listener.trans(response);
                    }
                });
    }

    private RetrofitBasicResponseObserver<BasicResponse<JsonObject>> getPulseSpeedResponseObserver() {
        if (pulseSpeedResponseObserver == null) {
            pulseSpeedResponseObserver = new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>(mContext) {
                @Override
                public void onSuccess(BasicResponse<JsonObject> response) {
                    super.onSuccess(response);
                    sendMsg(ApiEnum.PULSE_SPEED_API_NAME.message, HTTP_SUCCESS);
                    doPulseSpeedAPIDelay();
                }

                @Override
                public void onFail(BasicResponse<JsonObject> response) {
                    super.onFail(response);
                    sendMsg(ApiEnum.PULSE_SPEED_API_NAME.message + " onFail", response.getMsg());
                    if (isLimited()) {
                        removeAuthorizeCallback();
                    } else {
                        doPulseSpeedAPIDelay();
                    }
                }

                @Override
                public void onError(Throwable e) {
                    super.onError(e);
                    sendMsg(ApiEnum.PULSE_SPEED_API_NAME.message + " onError", e.toString());
                    if (isLimited()) {
                        removeAuthorizeCallback();
                    } else {
                        pulseSpeedAPI();
                    }
                }
            };
        }
        return pulseSpeedResponseObserver;
    }

    /**
     * pulseSpeedAPI
     */
    private void pulseSpeedAPI() {
        if (!authorize) {
            return;
        }
        params = getNewParams();
        params.put("HandlerId", getBasicResponse().getHandlerId());
        params.put("Version", BuildConfig.VERSION_NAME);
        getApiLoader().postJsonObserveJsonParam(ApiConstant.PULSE_SPEED_API, params)
                .subscribe(getPulseSpeedResponseObserver());
    }

    private Runnable pulseSpeedRunnable = new Runnable() {
        @Override
        public void run() {
            pulseSpeedAPI();
        }
    };

    private void doPulseSpeedAPIDelay() {
        if (!authorize) {
            return;
        }
        handler.postDelayed(pulseSpeedRunnable, DEFAULT_TIMEOUT * 1000L);
    }

    private Runnable authorizeRunnable = new Runnable() {
        @Override
        public void run() {
            authorize = false;
//            handler.removeCallbacks(pulseSpeedRunnable);
            removePulseSpeedCallback(true);
            authorizeAPI(null);
        }
    };

    private void doAuthorizeAPIDelay() {
        handler.postDelayed(authorizeRunnable, DEFAULT_AUTHORIZE_DELAY_TASK);
    }

    /**
     * authorizeAPI
     *
     * @param listener TransApiResultListener
     */
    public void authorizeAPI(final TransApiResultListener<String> listener) {
        if (listener != null) {
            removeAuthorizeCallback();
        }
        params = getNewParams();
        params.put("HandlerId", getBasicResponse().getHandlerId());
        String desData = getDesEncodeData();
        if (TextUtils.isEmpty(desData)) {
            sendMsg(ApiEnum.AUTHORIZE_API_NAME.message, mContext.getString(R.string.des_encode_data_error));
            return;
        }
        params.put("Data", desData);
        getApiLoader().postJsonObserveJsonParam(ApiConstant.AUTHORIZE_API, params)
                .subscribe(new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<JsonObject> response) {
                        super.onSuccess(response);
//                        LogUtil.log("authorizeAPI : " + response.toString());
                        authorize = true;
                        mLongTaskApiLoader = null;
                        pulseSpeedAPI();
                        sendMsg(ApiEnum.AUTHORIZE_API_NAME.message, HTTP_SUCCESS);
                        updateBasicResponse(response, ApiEnum.AUTHORIZE_API_NAME);
                        doAuthorizeAPIDelay();
                        if (listener != null) {
                            listener.trans(HTTP_SUCCESS);
                        }
                    }

                    @Override
                    public void onFail(BasicResponse<JsonObject> response) {
                        super.onFail(response);
                        authorize = false;
                        sendMsg(ApiEnum.AUTHORIZE_API_NAME.message, response.getMsg());
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        authorize = false;
                        sendMsg(ApiEnum.AUTHORIZE_API_NAME.message, e.toString());
                    }
                });
    }

    /**
     * @param verifyResult boolean
     * @param listener     TransApiResultListener
     */
    public void accountCheckAPI(boolean verifyResult, final TransApiResultListener<String> listener) {
        params = getNewParams();
        params.put("MerchantAccountId", getBasicResponse().getMerchantAccountId());
        params.put("Verify", verifyResult);
        getApiLoader().postJsonObserveDESRequestBody(ApiConstant.ACCOUNT_CHECK_API, params)
                .subscribe(new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<JsonObject> response) {
                        super.onSuccess(response);
                        listener.trans(ApiEnum.ACCOUNT_CHECK_API_NAME.message + " : " + HTTP_SUCCESS);
                    }

                    @Override
                    public void onFail(BasicResponse<JsonObject> response) {
                        super.onFail(response);
                        sendMsg(ApiEnum.ACCOUNT_CHECK_API_NAME.message, response.getMsg());
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        sendMsg(ApiEnum.ACCOUNT_CHECK_API_NAME.message, e.toString());
                    }
                });
    }

    private String getDesEncodeData() {
        JSONObject object = new JSONObject();
        String ip = sharedPreferenceUtil.SP_READ(mContext, SP_KEY_DEVICE_IP);
        if (TextUtils.isEmpty(ip)) {
            LogUtil.log("ip error ,need register again");
            return null;
        }
        final String CpuId = getDeviceId();
        if (TextUtils.isEmpty(CpuId)) {
            LogUtil.log("deviceId error ,need permission");
            return null;
        }
        try {
            object.put("HandlerId", getBasicResponse().getHandlerId());
            object.put("MechantAccount", getAliAccount(mContext));
            object.put("CpuId", CpuId);
            object.put("Ip", ip);
            object.put("Version", BuildConfig.VERSION_NAME);
            LogUtil.log("getDesEncodeData : " + object.toString());
        } catch (JSONException e) {
            e.printStackTrace();
            LogUtil.log("getDesEncodeData object error : " + e.toString());
            return null;
        }
        try {
//            LogUtil.log("key : " + getBasicResponse().getRegisterCode());
            return PayDESUtil.encode(getBasicResponse().getRegisterCode(), object.toString());
        } catch (Exception e) {
            e.printStackTrace();
            LogUtil.log("getDesEncodeData key error : " + e.toString());

        }
        return null;
    }

    private RetrofitBasicResponseObserver<BasicResponse<JsonObject>> getTaskApiServer() {
        if (taskApiServer == null) {
            taskApiServer = new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>(mContext) {
                @Override
                public void onSuccess(BasicResponse<JsonObject> response) {
                    super.onSuccess(response);
                    sendMsg(ApiEnum.TASK_API_NAME.message, response.toString());
                    updateBasicResponse(response, ApiEnum.TASK_API_NAME);
                    if (response.getTaskType() == 3
                            || response.getTaskType() == 4 || response.getTaskType() == 5) {
                        if (isTaskNull(mContext)) {
                            insertTask(mContext, response);
                            mContext.sendBroadcast(new Intent(ACTION_QUERY_ORDER));
                        } else {
                            insertTask(mContext, response);
                            LogUtil.log(ApiEnum.TASK_API_NAME.message
                                    + " : Please wait while in the mission");
                        }
                    }
                    getServerTaskAPI(1);
                }

                @Override
                public void onFail(BasicResponse<JsonObject> response) {
                    super.onFail(response);
                    getServerTaskAPI(1);
                    sendMsg(ApiEnum.TASK_API_NAME.message, response.toString());
                }

                @Override
                public void onError(Throwable e) {
                    super.onError(e);
                    if (isLimited()) {
                        longConnectStatus = 2;
                        removeAuthorizeCallback();
                        sendMsg(ApiEnum.TASK_API_NAME.message, mContext.getString(R.string.api_error_time_limited));
                    } else {
                        sendMsg(ApiEnum.TASK_API_NAME.message, e.toString());
                        getServerTaskAPI(1);
                    }
                }
            };
        }
        return taskApiServer;
    }

    public void getServerTaskAPI(int status) {
        if (status == 0 && longConnectStatus == 1) {
            return;
        }
        longConnectStatus = 1;
        JsonParams params = getNewParams();
        params.put("HandlerId", getBasicResponse().getHandlerId());
        params.put("SystemCode", getBasicResponse().getSystemCode());
        params.put("PayPlat", Integer.parseInt(PAYMENT));
        ApiLoader apiLoader = getLongTaskApiLoader();
        if (apiLoader == null) {
            sendMsg(ApiEnum.TASK_API_NAME.message, mContext.getString(R.string.task_long_connect_url_error));
            return;
        }
        String sign = getSign(params);
        apiLoader.postJsonObserveJsonParam(sign, params)
                .subscribe(getTaskApiServer());
    }

    private String getSign(JsonParams params) {
        String content = params.getJsonObject() + PAY_LONG_CONNECT_KEY;
        return PayMD5Util.getMD5(content);
    }

    private void sendMsg(String type, String content) {
        Intent intent = new Intent(ACTION_SHOW_LOG);
        intent.putExtra(SHOW_LOG_CONTENT, type + " : " + content);
        mContext.sendBroadcast(intent);
    }

    public void removeAuthorizeCallback() {
        handler.removeCallbacks(authorizeRunnable);
        if (authorize) {
            sendMsg(ApiEnum.AUTHORIZE_API_NAME.message, "stop");
            authorize = false;
            removePulseSpeedCallback(true);
        } else {
            removePulseSpeedCallback(false);
        }
    }

    private void removePulseSpeedCallback(boolean showLog) {
        if (showLog) {
            sendMsg(ApiEnum.PULSE_SPEED_API_NAME.message, "stop");
        }
        handler.removeCallbacks(pulseSpeedRunnable);
    }

    public void cleanBasicResponse() {
        mBasicResponse = null;
    }
}
